var fileKey = "fileList";
var baseUrl = "http://127.0.0.1:8080";

// 格式化文件大小
function formatFileSize(bytes) {
  if (bytes === 0) return "0 Bytes";
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
}

// 格式化时间
function formatDateTime(dateTimeStr) {
  const date = new Date(dateTimeStr);
  return date.toLocaleString();
}

// 计算文件MD5
async function calculateFileMD5(file) {
  return new Promise((resolve, reject) => {
    const chunkSize = 2097152; // 每次读取 2MB
    const spark = new SparkMD5.ArrayBuffer();
    const fileReader = new FileReader();
    let currentChunk = 0;
    const chunks = Math.ceil(file.size / chunkSize);

    fileReader.onload = function (e) {
      spark.append(e.target.result); // 将读取的数据添加到 spark
      currentChunk++;

      if (currentChunk < chunks) {
        // 继续读取下一块
        loadNext();
      } else {
        // 完成所有块的读取，生成最终的 MD5
        const md5 = spark.end();
        resolve(md5);
      }
    };

    fileReader.onerror = function (e) {
      reject(new Error("文件读取失败"));
    };

    function loadNext() {
      const start = currentChunk * chunkSize;
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
      const chunk = file.slice(start, end);
      fileReader.readAsArrayBuffer(chunk);
    }

    loadNext(); // 开始读取第一块
  });
}

// 获取文件列表
async function getFileList(fileName = "", pageNum = 1, pageSize = 10) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: baseUrl + "/api/upload/v2/list",
      type: "GET",
      data: {
        fileName: fileName,
        pageNum: pageNum,
        pageSize: pageSize,
      },
      success: function (res) {
        if (res.code == 200) {
          resolve(res.data);
        } else {
          reject(new Error(res.msg || "获取文件列表失败"));
        }
      },
      error: function (err) {
        reject(new Error("获取文件列表失败"));
      },
    });
  });
}

// 删除文件
async function deleteFile(identifier) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: baseUrl + "/api/upload/v2/remove/" + identifier,
      type: "DELETE",
      success: function (res) {
        if (res.code == 200) {
          resolve(true);
        } else {
          reject(new Error(res.msg || "删除文件失败"));
        }
      },
      error: function (err) {
        reject(new Error("删除文件失败"));
      },
    });
  });
}

function addList(fileUrl, fileName, fileSize, identifier, uploadTime) {
  // 添加到DOM
  $("#file-list").append(`
    <li class="list-group-item file-item">
      <div class="file-info">
        <a href="${fileUrl}" target="_blank">${fileName}</a>
        <span class="file-size">${fileSize ? formatFileSize(fileSize) : ""} - ${
    uploadTime ? formatDateTime(uploadTime) : new Date().toLocaleString()
  }</span>
      </div>
      <button class="btn btn-sm btn-outline-danger delete-file" data-identifier="${identifier}">删除</button>
    </li>
  `);

  // 隐藏"暂无文件"消息
  $("#no-files-message").hide();
}

async function fillList() {
  try {
    const fileList = await getFileList();
    if (fileList && fileList.length) {
      for (const fileInfo of fileList) {
        addList(fileInfo.url, fileInfo.fileName, fileInfo.fileSize, fileInfo.identifier, fileInfo.uploadTime);
      }
      // 隐藏"暂无文件"消息
      $("#no-files-message").hide();
    } else {
      // 显示"暂无文件"消息
      $("#no-files-message").show();
    }
  } catch (error) {
    console.error("获取文件列表失败:", error);
    Toast.fire({
      icon: "error",
      title: "获取文件列表失败",
    });
  }
}

// 更新进度条
function updateProgress(percent) {
  // 确保进度在0-100之间
  percent = Math.max(0, Math.min(100, Math.round(percent)));

  // 显示进度条
  $(".progress").show();

  // 根据进度选择颜色
  let colorClass = "bg-primary";
  if (percent < 30) {
    colorClass = "bg-danger";
  } else if (percent < 60) {
    colorClass = "bg-warning";
  } else if (percent < 90) {
    colorClass = "bg-info";
  } else {
    colorClass = "bg-success";
  }

  // 移除所有颜色类并添加当前颜色
  const progressBar = $("#upload-progress-bar");
  progressBar.removeClass("bg-danger bg-warning bg-info bg-success bg-primary");
  progressBar.addClass(colorClass);

  // 设置进度条宽度和文本
  progressBar.css("width", percent + "%").attr("aria-valuenow", percent);
  progressBar.text(percent + "%"); // 在进度条内显示百分比

  // 更新状态文本
  $("#upload-status").text(percent + "% 已上传");

  // 调试输出
  console.log("进度更新:", percent + "%", "颜色:", colorClass);
}

// 重置进度条
function resetProgress() {
  $(".progress").hide();
  const progressBar = $("#upload-progress-bar");
  progressBar.removeClass("bg-danger bg-warning bg-info bg-success bg-primary");
  progressBar.addClass("bg-primary");
  progressBar.css("width", "0%").attr("aria-valuenow", 0);
  progressBar.text("");
  $("#upload-status").text("");
}

async function uploadFile(file) {
  var fileSize = file.size;
  var chunkSize = 5 * 1024 * 1024; // 分块大小

  // 显示上传状态
  $("#upload-status").text("准备上传...");
  $(".progress").show();
  updateProgress(0);

  try {
    // 计算文件唯一标识符
    const identifier = await calculateFileMD5(file);
    console.log("文件标识:", identifier);

    // 先尝试秒传
    const secondUploadResult = await trySecondUpload(file, identifier);
    if (secondUploadResult) {
      // 秒传成功
      resetProgress();
      Toast.fire({
        icon: "success",
        title: "秒传成功",
      });
      // 刷新文件列表
      await refreshFileList();
      return;
    }

    if (fileSize <= chunkSize) {
      // 小文件上传
      const result = await uploadSmallFile(file, identifier);
      // 小文件上传成功后会自动刷新列表
    } else {
      // 大文件分片上传
      const result = await uploadLargeFile(file, identifier, chunkSize);
      // 刷新文件列表
      await refreshFileList();
    }
  } catch (error) {
    console.error("上传错误:", error);
    resetProgress();
    Toast.fire({
      icon: "error",
      title: "上传失败: " + (error.message || "未知错误"),
    });
  }
}

// 尝试秒传
async function trySecondUpload(file, identifier) {
  return new Promise((resolve, reject) => {
    const params = {
      fileName: file.name,
      identifier: identifier,
      fileSize: file.size,
      contentType: file.type,
    };

    $.ajax({
      url: baseUrl + "/api/upload/v2/second_upload",
      type: "POST",
      contentType: "application/json",
      data: JSON.stringify(params),
      success: function (res) {
        if (res.code == 200 && res.data === true) {
          // 秒传成功，通常需要返回文件信息，但这里示例简化处理
          resolve({
            url: baseUrl + "/files/" + file.name, // 模拟一个URL，实际应从后端返回
            identifier: identifier,
            uploadTime: new Date().toLocaleString(),
          });
        } else {
          // 秒传失败，走正常上传流程
          resolve(null);
        }
      },
      error: function (err) {
        // 秒传接口失败也走正常上传，不抛出异常
        console.warn("秒传检查失败:", err);
        resolve(null);
      },
    });
  });
}

// 清空文件列表并重新加载
async function refreshFileList() {
  $("#file-list").empty();
  await fillList();
}

// 上传小文件
async function uploadSmallFile(file, identifier) {
  return new Promise((resolve, reject) => {
    var formData = new FormData();
    formData.append("file", file);
    formData.append("fileName", file.name);
    formData.append("contentType", file.type);
    formData.append("identifier", identifier);

    $.ajax({
      url: baseUrl + "/api/upload/v2/upload",
      type: "POST",
      contentType: false,
      processData: false,
      data: formData,
      xhr: function () {
        var xhr = new window.XMLHttpRequest();
        xhr.upload.addEventListener(
          "progress",
          function (evt) {
            if (evt.lengthComputable) {
              var percentComplete = Math.round((evt.loaded / evt.total) * 100);
              updateProgress(percentComplete);
            }
          },
          false
        );
        return xhr;
      },
      success: function (res) {
        resetProgress();
        if (res.code == 200) {
          Toast.fire({
            icon: "success",
            title: "文件上传成功",
          });
          // 刷新文件列表
          refreshFileList();
        } else {
          const errorMsg = res.msg || "上传失败";
          Toast.fire({
            icon: "error",
            title: errorMsg,
          });
          reject(new Error(errorMsg));
        }
      },
      error: function (err) {
        resetProgress();
        const errorMsg = "上传失败，请重试";
        Toast.fire({
          icon: "error",
          title: errorMsg,
        });
        reject(new Error(errorMsg));
      },
    });
  });
}

// 上传大文件
async function uploadLargeFile(file, identifier, chunkSize) {
  try {
    // 计算总分片数
    const totalChunks = Math.ceil(file.size / chunkSize);

    // 1. 先检查文件分片上传进度
    let uploadedPartNumbers = [];
    let taskExists = false;

    try {
      const progressResult = await checkUploadProgress(identifier);
      if (progressResult) {
        taskExists = true;
        const uploadedParts = progressResult.existPartList || [];
        uploadedPartNumbers = uploadedParts.map((part) => part.partNumber);
        console.log("已上传的分片:", uploadedPartNumbers);

        // 更新初始进度
        const initialProgress = Math.round((uploadedPartNumbers.length / totalChunks) * 100);
        updateProgress(initialProgress);

        Toast.fire({
          icon: "info",
          title: `发现未完成的上传任务，已完成 ${uploadedPartNumbers.length}/${totalChunks} 个分片`,
          timer: 2000,
        });
      }
    } catch (error) {
      console.log("无法获取上传进度或任务不存在:", error);
      // 如果检查失败，假设任务不存在，后续会创建新任务
    }

    // 2. 如果任务不存在，则初始化分片上传任务
    if (!taskExists) {
      console.log("创建新的分片上传任务");
      await initFileChunkTask(file, identifier);
    }

    // 3. 逐个上传未完成的分片
    const uploadedChunks = [...uploadedPartNumbers]; // 复制已上传的分片编号
    for (let i = 1; i <= totalChunks; i++) {
      // 如果分片已上传，跳过
      if (uploadedPartNumbers.includes(i)) {
        console.log(`分片 ${i} 已上传，跳过`);
        continue;
      }

      try {
        // 准备分片数据
        const start = (i - 1) * chunkSize;
        const end = Math.min(file.size, start + chunkSize);
        const chunk = file.slice(start, end);

        // 直接上传分片到后端API
        const formData = new FormData();
        formData.append("file", new Blob([chunk], { type: "application/octet-stream" }));

        const response = await $.ajax({
          url: baseUrl + `/api/upload/v2/upload_part/${identifier}/${i}`,
          type: "POST",
          data: formData,
          contentType: false,
          processData: false,
          xhr: function () {
            const xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener(
              "progress",
              function (evt) {
                if (evt.lengthComputable) {
                  // 计算单个分片的进度
                  const partProgress = Math.round((evt.loaded / evt.total) * 100);
                  console.log(`分片 ${i} 上传进度: ${partProgress}%`);

                  // 计算总体进度：已完成的分片 + 当前分片的进度比例
                  const totalProgress = Math.round(
                    ((uploadedChunks.length + evt.loaded / evt.total) / totalChunks) * 100
                  );
                  // 更新UI进度条
                  updateProgress(totalProgress);
                }
              },
              false
            );
            return xhr;
          },
        });

        if (response.code == 200) {
          uploadedChunks.push(i);
          // 更新总进度
          const percentComplete = Math.round((uploadedChunks.length / totalChunks) * 100);
          updateProgress(percentComplete);
        } else {
          throw new Error(response.msg || "分片上传失败");
        }
      } catch (error) {
        console.error(`分片 ${i} 上传失败:`, error);
        throw new Error(`分片 ${i} 上传失败: ${error.message || "未知错误"}`);
      }
    }

    // 4. 合并分片
    $("#upload-status").text("正在合并分片...");
    const mergeResult = await mergeFileChunks(file, identifier, totalChunks);

    // 5. 上传完成
    resetProgress();
    Toast.fire({
      icon: "success",
      title: "文件上传成功",
    });
    return mergeResult;
  } catch (error) {
    console.error("大文件上传失败:", error);
    throw error;
  }
}

// 初始化分片上传任务
async function initFileChunkTask(file, identifier) {
  return new Promise((resolve, reject) => {
    const params = {
      fileName: file.name,
      identifier: identifier,
      totalSize: file.size,
      chunkSize: 5 * 1024 * 1024,
      totalChunks: Math.ceil(file.size / (5 * 1024 * 1024)),
      contentType: file.type,
    };

    $.ajax({
      url: baseUrl + "/api/upload/v2/init_file_chunk_task",
      type: "POST",
      contentType: "application/json",
      data: JSON.stringify(params),
      success: function (res) {
        if (res.code == 200) {
          resolve(res.data);
        } else {
          reject(new Error(res.msg || "初始化上传任务失败"));
        }
      },
      error: function (err) {
        reject(new Error("初始化上传任务失败"));
      },
    });
  });
}

// 获取分片上传URL
async function getFileChunkUploadUrl(identifier, partNumber) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: baseUrl + `/api/upload/v2/get_file_chunk_upload_url/${identifier}/${partNumber}`,
      type: "GET",
      success: function (res) {
        if (res.code == 200) {
          resolve(res.data);
        } else {
          reject(new Error(res.msg || "获取上传URL失败"));
        }
      },
      error: function (err) {
        reject(new Error("获取上传URL失败"));
      },
    });
  });
}

// 将分片上传到预签名URL（已废弃，请直接使用上传API）
async function uploadChunkToUrl(url, chunk, retryCount = 3, retryDelay = 1000) {
  console.warn("uploadChunkToUrl 方法已废弃，请直接使用 upload_part API上传分片");
  return new Promise(async (resolve, reject) => {
    let attempts = 0;

    const attemptUpload = async () => {
      attempts++;
      try {
        // 解析URL，获取最后两个路径参数
        const urlObj = new URL(url);
        const pathParts = urlObj.pathname.split("/");
        const identifier = pathParts[pathParts.length - 2];
        const partNumber = parseInt(pathParts[pathParts.length - 1], 10);

        // 使用FormData构建请求
        const formData = new FormData();
        formData.append("file", new Blob([chunk], { type: "application/octet-stream" }));

        // 通过后端代理上传分片
        const response = await $.ajax({
          url: baseUrl + `/api/upload/v2/upload_part/${identifier}/${partNumber}`,
          type: "POST",
          data: formData,
          contentType: false,
          processData: false,
          xhr: function () {
            const xhr = new window.XMLHttpRequest();
            xhr.upload.addEventListener(
              "progress",
              function (evt) {
                if (evt.lengthComputable) {
                  console.log(`分片上传进度: ${Math.round((evt.loaded / evt.total) * 100)}%`);
                }
              },
              false
            );
            return xhr;
          },
        });

        if (response.code == 200) {
          resolve(response.data);
        } else {
          throw new Error(response.msg || "分片上传失败");
        }
      } catch (error) {
        console.warn(`分片上传失败 (尝试 ${attempts}/${retryCount}):`, error);

        if (attempts < retryCount) {
          await new Promise((r) => setTimeout(r, retryDelay));
          return attemptUpload();
        }

        reject(new Error(`分片上传失败 (已重试 ${retryCount} 次): ${error.message || "未知错误"}`));
      }
    };

    if (!url || !chunk) {
      return reject(new Error("无效的上传URL或分片数据"));
    }

    attemptUpload();
  });
}

// 检查上传进度
async function checkUploadProgress(identifier) {
  return new Promise((resolve, reject) => {
    $.ajax({
      url: baseUrl + `/api/upload/v2/file_chunk_upload_progress/${identifier}`,
      type: "GET",
      success: function (res) {
        if (res.code == 200) {
          resolve(res.data);
        } else {
          reject(new Error(res.msg || "获取上传进度失败"));
        }
      },
      error: function (err) {
        reject(new Error("获取上传进度失败"));
      },
    });
  });
}

// 合并文件分片
async function mergeFileChunks(file, identifier, totalChunks) {
  return new Promise((resolve, reject) => {
    const params = {
      fileName: file.name,
      identifier: identifier,
      totalSize: file.size,
      totalChunks: totalChunks,
      contentType: file.type,
    };

    $.ajax({
      url: baseUrl + "/api/upload/v2/merge_file_chunk",
      type: "POST",
      contentType: "application/json",
      data: JSON.stringify(params),
      success: function (res) {
        if (res.code == 200) {
          // 假设服务器返回合并后的文件URL
          resolve(true);
        } else {
          reject(new Error(res.msg || "合并文件失败"));
        }
      },
      error: function (err) {
        reject(new Error("合并文件失败"));
      },
    });
  });
}

// 绑定拖拽区域事件
function bindDropZoneEvents() {
  const dropZone = $("#drop-zone");

  // 防止浏览器默认行为（如打开文件）
  ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
    dropZone.on(eventName, function (e) {
      e.preventDefault();
      e.stopPropagation();
    });
  });

  // 添加视觉反馈
  ["dragenter", "dragover"].forEach((eventName) => {
    dropZone.on(eventName, function () {
      dropZone.addClass("drag-over");
    });
  });

  ["dragleave", "drop"].forEach((eventName) => {
    dropZone.on(eventName, function () {
      dropZone.removeClass("drag-over");
    });
  });

  // 处理文件拖放
  dropZone.on("drop", function (e) {
    const files = e.originalEvent.dataTransfer.files;
    if (files && files.length) {
      uploadFile(files[0]);
    }
  });

  // 点击拖拽区域也触发文件选择
  dropZone.on("click", function () {
    $("input#file").click();
  });
}

$(function () {
  // 绑定上传按钮点击事件
  $("button#uploadBtn").on("click", function () {
    $("input#file").click();
  });

  // 绑定文件选择变化事件
  $("input#file").on("change", function () {
    var files = $(this).prop("files");
    if (files && files.length) {
      var file = files[0];
      uploadFile(file);
      // 清空input，允许重复上传相同文件
      $(this).val("");
    }
  });

  // 绑定拖拽区域事件
  bindDropZoneEvents();

  // 绑定删除按钮点击事件（使用事件委托）
  $(document).on("click", ".delete-file", async function () {
    const identifier = $(this).data("identifier");
    const $listItem = $(this).closest("li");

    const result = await Swal.fire({
      title: "确定删除？",
      text: "此操作将从服务器永久删除该文件，且无法恢复",
      icon: "warning",
      showCancelButton: true,
      confirmButtonText: "确定删除",
      cancelButtonText: "取消",
      confirmButtonColor: "#dc3545",
    });

    if (result.isConfirmed) {
      try {
        await deleteFile(identifier);
        $listItem.remove();

        // 如果列表为空，显示"暂无文件"消息
        if ($("#file-list").children().length === 0) {
          $("#no-files-message").show();
        }

        Toast.fire({
          icon: "success",
          title: "文件已删除",
        });
      } catch (error) {
        Toast.fire({
          icon: "error",
          title: "删除失败: " + error.message,
        });
      }
    }
  });

  // 绑定刷新按钮点击事件
  $("#refreshList").on("click", async function () {
    const $btn = $(this);
    const $icon = $btn.find("i");

    // 添加加载动画
    $btn.prop("disabled", true);
    $icon.addClass("rotate-animation");

    try {
      await refreshFileList();
    } catch (error) {
      Toast.fire({
        icon: "error",
        title: "刷新失败: " + error.message,
      });
    } finally {
      // 移除加载动画
      $btn.prop("disabled", false);
      $icon.removeClass("rotate-animation");
    }
  });

  // 初始化文件列表
  fillList();
});
